package com.zpark.cloud.alibaba.filters;

import com.alibaba.nacos.common.utils.StringUtils;
import lombok.Data;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import sun.security.krb5.internal.AuthorizationDataEntry;

import java.util.Arrays;
import java.util.List;

/**
 * @PackageName: com.zpark.cloud.alibaba.filters
 * @ClassName: AuthorizeGatewayFilterFactory
 * @Description:
 * @author: RZS
 * @date: 2023/6/25  15:58
 */
@Component
public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config> {

    private static final String AUTHORIZE_TOKEN = "token";

    public AuthorizeGatewayFilterFactory() {
        super(Config.class);
    }

    // 用于从配置文件中获取参数值，赋值到配置类中的属性上
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("tokenEnabled");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter(){
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                if (!config.tokenEnabled) {
                    return chain.filter(exchange);
                }
                ServerHttpRequest request = exchange.getRequest();
                HttpHeaders headers = request.getHeaders();
                String token = headers.getFirst(AUTHORIZE_TOKEN);
                if (token == null) {
                    token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
                }
                if (StringUtils.isEmpty(token)) {
                    return Mono.error(new ResponseStatusException(HttpStatus.UNAUTHORIZED, "token is Empty"));
                }

                /**
                 * 此时需要根据 token 查询Redis，看是否可以查到用户权限信息了
                 * 我这里做测试，没有引入Redis，所以模拟从Redis查询到数据了
                 */
                String authTokenFromRedis = "user:zhangsan,age=21";
                if (StringUtils.isEmpty(authTokenFromRedis)) {
                    return Mono.error(new ResponseStatusException(HttpStatus.UNAUTHORIZED, "token is error"));
                }

                //授权信息不为空，那就放行（真实项目中不会这么简单的，这里是测试）
                return chain.filter(exchange);
            }
        };
    }

    //创建一个静态内部类，成员变量的set/get方法必须要
    @Data
    public static class Config {
        // 控制是否开启认证
        private Boolean tokenEnabled;
    }
}
